package main

import (
	"bytes"
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	sc "github.com/hyperledger/fabric/protos/peer"
)

type SmartContract struct {
}

type Seller struct {
	SellerId string	`json:"sellerId"`
	Name string	`json:"name"`
    Address string `json:"address"`
}

type User struct {
	UserId string	`json:"userId"`
	Password string	`json:"password"`
	Role string `json:"role"`
	Org string `json:"org"`
	Add string `json:"add"`
	Edit string `json:"edit"`
	Delete string `json:"delete"`
}

func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response {
	return shim.Success(nil)
}

func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {

	function, args := APIstub.GetFunctionAndParameters()
	if function == "query" {
		return s.query(APIstub, args)
	}else if function == "create" {
		return s.create(APIstub, args)
	} else if function == "change" {
		return s.change(APIstub, args)
	} else if function == "delete" {
		return s.delete(APIstub, args)
	} else if function == "queryAll" {
		return s.queryAll(APIstub)
	} else if function == "initLedger" {
		return s.initLedger(APIstub)
	} else if function == "createUser" {
		return s.createUser(APIstub, args)
	}

	return shim.Error("Invalid Smart Contract function name.")
}

func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response {
	Sellers := []Seller{
		Seller{SellerId: "SE101", Name: "Prius1", Address: "blue"},
		Seller{SellerId: "SE102", Name: "Prius2", Address: "blue"},
		Seller{SellerId: "SE103", Name: "Prius3", Address: "blue"},
	}

	i := 0
	for i < len(Sellers) {
		fmt.Println("i is ", Sellers[i])
		SellerAsBytes, _ := json.Marshal(Sellers[i])
		fmt.Println(SellerAsBytes)
		APIstub.PutState(Sellers[i].SellerId, SellerAsBytes)
		fmt.Println("Added", Sellers[i])
		i = i + 1
	}

	return shim.Success(nil)
}

func (s *SmartContract) query(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	DataAsBytes, _ := APIstub.GetState(args[0])
	fmt.Println(DataAsBytes)
	return shim.Success(DataAsBytes)
}

func (s *SmartContract) create(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	if len(args) != 3 {
		return shim.Error("Incorrect number of arguments. Expecting 3")
	}

	var Seller = Seller{SellerId: args[0], Name: args[1], Address: args[2]}

	SellerAsBytes, _ := json.Marshal(Seller)
	APIstub.PutState(args[0], SellerAsBytes)

	return shim.Success(nil)
}

func (t *SmartContract) delete(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	APIstub.DelState(args[0])
	return shim.Success(nil)
}

func (s *SmartContract) change(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	s.delete(APIstub, args)
	s.create(APIstub, args)
	return shim.Success(nil)
}

func (s *SmartContract) queryAll(APIstub shim.ChaincodeStubInterface) sc.Response {

	startKey := "SE0"
	endKey := "SE99999999999"

	resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Record\":")
		// Record is a JSON object, so we write as-is
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	fmt.Printf("- queryAllSellers:\n%s\n", buffer.String())

	return shim.Success(buffer.Bytes())
}

func (s *SmartContract) createUser(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 7 {
		return shim.Error("Incorrect number of arguments. Expecting 7")
	}

	var User = User{UserId: args[0], Password: args[1], Role: args[2], Org: args[3], Add: args[4], Edit: args[5], Delete: args[6]}
	UserAsBytes, _ := json.Marshal(User)
	APIstub.PutState(args[0], UserAsBytes)

	return shim.Success(nil)
}

func main() {
	err := shim.Start(new(SmartContract))
	if err != nil {
		fmt.Printf("Error creating new Smart Contract: %s", err)
	}
}
